/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import path from 'path';

import { IncrementalExecTask } from '../../../external/task/incremental-exec-task.js';
import { IncrementalTask } from '../../../external/task/incremental-task.js';
import { JsonReader } from '../../../util/json-reader.js';
import { DefaultTaskSnapshot } from '../core/default-task-snapshot.js';
import { TaskSnapshot } from '../core/task-snapshot.js';
import { TaskBuiltIn } from '../util/task-built-in.js';

import { TaskSnapshotGenerator } from './task-snapshot-generator.js';
import Execution = TaskBuiltIn.Execution;
import snapshotSerializationReplacer = TaskBuiltIn.snapshotSerializationReplacer;
import snapshotSerializationReceiver = TaskBuiltIn.snapshotSerializationReceiver;

export class DefaultTaskSnapshotGenerator implements TaskSnapshotGenerator {
  snapshot(task: IncrementalTask): TaskSnapshot {
    const snapshot = new DefaultTaskSnapshot(task);
    if (task instanceof IncrementalExecTask) {
      snapshot.addInput(Execution.COMMAND, task.declareExecutionCommand());
      snapshot.addInput(Execution.TOOLCHAIN, task.declareExecutionTool());
      const executionEnv = task.declareExecutionEnv();
      const env: string[] = [];
      Array.from(executionEnv.keys())
        .sort()
        .forEach((key) => env.push(`${key}:${executionEnv.get(key)}${path.delimiter}`));
      snapshot.addInput(Execution.ENV, env.join());
    }
    return snapshot;
  }

  loadSnapshotFromJson(text: string): TaskSnapshot {
    const snapshot = JsonReader.parseJsonText<DefaultTaskSnapshot>(text, {} as DefaultTaskSnapshot, snapshotSerializationReceiver);
    Object.setPrototypeOf(snapshot, DefaultTaskSnapshot.prototype);
    return snapshot;
  }

  loadSnapshotCacheFromJson(text: string): Map<string, TaskSnapshot> {
    const obj = JsonReader.parseJsonText(text, new Map<string, TaskSnapshot>(), snapshotSerializationReceiver);
    const collection: Map<string, TaskSnapshot> = new Map<string, TaskSnapshot>();
    for (const [key, value] of Object.entries(obj)) {
      collection.set(key, Object.setPrototypeOf(value, DefaultTaskSnapshot.prototype));
    }
    return collection;
  }

  serializeSnapshotCacheToJson(collection: Map<string, TaskSnapshot>): string {
    const map = Object.fromEntries(collection.entries());
    return JSON.stringify(map, snapshotSerializationReplacer);
  }
}
